#include "BSem.h"

void bsem_init(BSem* bsem, int value)
{
    if (value < 0 || value > 1) {
        error(1, 0, "bsem_init(): value must be 0 or 1");
    }
    pthread_cond_init(&bsem->cond, NULL);   // 采用默认属性
    pthread_mutex_init(&bsem->mutex, NULL);
    bsem->value = value;
}

// P操作
void bsem_wait(BSem* bsem)
{
    // 获取互斥锁
    pthread_mutex_lock(&bsem->mutex);
    // 条件：bsem->value == 1
    while (bsem->value != 1) {
        pthread_cond_wait(&bsem->cond, &bsem->mutex);
        // wait返回时，条件不一定成立！(虚假唤醒)
    } // bsem->value == 1
    bsem->value = 0;    // 获取了一个资源
    pthread_mutex_unlock(&bsem->mutex);
}

// 当条件成立时，调用bsem_post
void bsem_post(BSem* bsem)
{
    pthread_mutex_lock(&bsem->mutex);
    bsem->value = 1;
    pthread_cond_signal(&bsem->cond);
    pthread_mutex_unlock(&bsem->mutex);
}

// 当条件成立时，调用bsem_postall
void bsem_postall(BSem* bsem)
{
    pthread_mutex_lock(&bsem->mutex);
    bsem->value = 1;
    pthread_cond_broadcast(&bsem->cond);
    pthread_mutex_unlock(&bsem->mutex);
}

void bsem_reset(BSem* bsem)
{
    pthread_mutex_lock(&bsem->mutex);
    bsem->value = 0;
    pthread_mutex_unlock(&bsem->mutex);
}

void bsem_destroy(BSem* bsem)
{
    pthread_cond_destroy(&bsem->cond);
    pthread_mutex_destroy(&bsem->mutex);
}

#ifdef BSEM_TEST

void* start_routine(void* arg)
{
    BSem* bsem = (BSem*) arg;
    bsem_wait(bsem);
    // 拿到了资源， bsem->value = 0
    printf("%lx: 进入临界区\n", pthread_self());
    sleep(1);   // 模拟操作临界资源
    printf("%lx: 退出临界区\n", pthread_self());
    bsem_post(bsem);
}

int main(int argc, char* argv[])
{
    BSem bsem;  // 栈上的变量
    bsem_init(&bsem, 1);    

    pthread_t threads[10];
    for (int i = 0; i < 10; i++) {
        pthread_create(threads + i, NULL, start_routine, (void*)&bsem);
    }

    // 主线程等待子线程终止
    for (int i = 0; i < 10; i++) {
        pthread_join(threads[i], NULL);
    }

    return 0;
}
#endif

